from datetime import datetime, timedelta

import pandas as pd
import numpy as np
from keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.preprocessing import MinMaxScaler, LabelEncoder
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from sklearn.metrics import mean_squared_error, mean_absolute_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import warnings
from dateutil.parser import parse
import joblib
import tensorflow as tf


# category_features1 = np.array(['毛呢外套','毛针织衫','连衣裙','短外套','毛针织衫'])
# print(np.reshape(category_features1, (-1, 1)))

# 忽略警告信息
warnings.filterwarnings('ignore')

df2 = pd.read_excel('lstm2.xlsx')
data = df2[df2['product_code'] == 'LO2501008ZCYL'].copy()

data['date'] = pd.to_datetime(data['date'], format='%Y-%m-%d')
data.sort_values(by=['date', 'product_code'], inplace=True)
data.reset_index(drop=True, inplace=True)

# 特征提取：提取年、月、日作为特征
data['year'] = data['date'].dt.year
data['month'] = data['date'].dt.month
data['day'] = data['date'].dt.day

# 将品类转换为数值类型（假设品类是字符串形式）
le = LabelEncoder()
data['category'] = le.fit_transform(data['category'])

print("--------原始数据---------------- \n", data)

# 定义输入特征和目标变量
features = ['year', 'month', 'day', 'category', 'days_since_launch']
target = ['target_sales']

# 创建输入数据矩阵 X 和输出向量 y
X = []
y = []

for i in range(len(data) - 7):
    # 取过去 7 天的数据作为特征（根据时间窗口调整）
    start_idx = i
    end_idx = i + 7

    # 特征部分：取过去 7 天的支付日期、品类和销量
    feature_part = data[features].iloc[start_idx:end_idx, :4]
    # 将支付日期分解为年、月、日（已经处理过）
    date_features = np.array(feature_part[['year', 'month', 'day']])
    #  部分转换为数值
    category_features = np.array(feature_part['category'])
    # 合并特征
    merged_features = np.concatenate([date_features, np.reshape(category_features, (-1, 1))], axis=1)
    X.append(merged_features)
    # 目标变量：取未来 7 天的销量（这里假设目标是预测下一天的销量，可以调整 window_size）
    y.append(data[target].iloc[end_idx])

# 将 X 和 y 转换为 numpy 数组
X = np.array(X)
y = np.array(y)

print("--------原始数据 X---------------- \n", X)
print("--------原始数据 X shape---------------- \n", X.shape)
print("--------原始数据 y---------------- \n", y)
print("--------原始数据 y shape---------------- \n", y.shape)


# 标准化特征和目标变量
scaler_X = MinMaxScaler()
print('----X 标准化 数据结构处理1---- \n', X.shape[0], X.shape[1], X.shape[-1])
print('----X 标准化 数据结构处理2---- \n', X.reshape(-1, X.shape[-1]))
X_scaled = scaler_X.fit_transform(X.reshape(-1, X.shape[-1])).reshape(X.shape)

print('----X 标准化 数据结构处理3---- \n', X.reshape(-1, X.shape[-1]).reshape(X.shape))

scaler_y = MinMaxScaler()
print('----y 标准化 数据结构处理1---- \n', y.reshape(-1, 1), y.shape)
y_scaled = scaler_y.fit_transform(y.reshape(-1, 1)).reshape(y.shape)

# 划分训练集和测试集
train_samples = int(len(X_scaled) * 0.8)
test_samples = len(X_scaled) - train_samples

X_train_before_scaled = X[:train_samples]
y_train_before_scaled = y[:train_samples]
X_test_before_scaled = X[train_samples:]
y_test_before_scaled = y[train_samples:]


X_train = X_scaled[:train_samples]
y_train = y_scaled[:train_samples]

X_test = X_scaled[train_samples:]
y_test = y_scaled[train_samples:]

print('----------训练数据 X_train------\n', X_train.shape, '\n', X_train)
print('----------训练数据 y_train------\n', y_train.shape, '\n', y_train)

print('----------验证数据 X_test------\n', X_test.shape, '\n', X_test)
print('----------验证数据 y_test------\n', y_test.shape, '\n', y_test)


# 构建 LSTM 模型
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(7, 4)))
model.add(Dropout(0.2))
model.add(LSTM(units=50, return_sequences=False))
model.add(Dense(1))

# 编译模型
model.compile(loss='mean_squared_error', optimizer='adam')

model.fit(
    X_train,
    y_train,
    epochs=30,
    batch_size=32,
    validation_data=(X_test, y_test),
    callbacks=[EarlyStopping(monitor="val_loss", patience=20)]
)

model.save("./lstm2.h5")
model = tf.keras.models.load_model('./lstm2.h5')


# 评估模型性能
loss = model.evaluate(X_test, y_test)
print(f"------------测试集损失--------: {loss}")

y_train_pred = model.predict(X_train)
print("----y_train_pred 标准化结果------------\n", y_train_pred)


y_test_pred = model.predict(X_test)
print("----y_test_pred 标准化结果------------\n", y_test_pred)

y_pred_re = scaler_y.inverse_transform(y_train_pred)
print("----y_pred_re 反标准化结果------------\n", y_pred_re)

y_test_re = scaler_y.inverse_transform(y_test_pred)
print("----y_test_re 反标准化结果------------\n", y_test_re)


mse_train = mean_squared_error(y_train_before_scaled, y_pred_re)
test_train = mean_squared_error(y_test_before_scaled, y_test_re)
print("------训练集均方误差-----\n", mse_train)
print("------验证集均方误差-----\n", test_train)


# 假设我们要预测未来 7 天的销量
window_size = 7

# 准备输入数据进行预测
last_data_point = data.iloc[-1:]

print(last_data_point)

# 提取支付日期、品类和销量
payment_date = last_data_point['date']
category = last_data_point['category']
sales = last_data_point['target_sales']

# 处理支付日期（增加 7 天）
predicted_dates = []
for i in range(7):
    predicted_date = (pd.to_datetime(payment_date,  format='%Y-%m-%d') + timedelta(days=i + 1))
    predicted_dates.append(predicted_date)
    print(predicted_date)

# 将预测日期分解为年、月、日
date_features_pred = np.array([[d.year, d.month, d.day] for d in predicted_dates])
print(date_features_pred)

# 转换品类
category_features_pred = np.array([category] * 7)

# 合并特征
merged_features_pred = np.concatenate([np.reshape(date_features_pred, (-1, 3)),
                                       np.reshape(category_features_pred, (-1, 1))], axis=1)
print(merged_features_pred)
# 标准化特征
scaled_features_pred = scaler_X.fit_transform(merged_features_pred.reshape(-1, merged_features_pred.shape[1]))
print(scaled_features_pred)
# 重塑数据以适应 LSTM 输入格式 (samples, timesteps, features)
X_pred = np.reshape(scaled_features_pred, (1, 7, scaled_features_pred.shape[1]))
print(X_pred)
# 进行预测
y_pred_scaled = model.predict(X_pred)
print(y_pred_scaled)
# 反标准化预测结果
y_pred = scaler_y.inverse_transform(y_pred_scaled)
print(y_pred)
# 打印预测结果
for i in range(7):
    predicted_date_str = pd.to_datetime(predicted_dates[i], format='%Y-%m-%d')
    print(f"日期: {predicted_date_str}, 预测销量: {y_pred}")